#pragma once

#include "../common/Message.hpp"
#include "../common/Net.hpp"

namespace rpc
{
    namespace server
    {
        enum ValueType
        {
            BOOL = 0,
            INTEGRAL,
            NUMERIC,
            STRING,
            ARRAY,
            OBJECT
        };

        class ServiceDescribe
        {
        private:
            bool check(ValueType &type, const Json::Value &param)
            {
                switch (type)
                {
                case ValueType::BOOL:
                    return param.isBool();
                case ValueType::INTEGRAL:
                    return param.isIntegral();
                case ValueType::NUMERIC:
                    return param.isNumeric();
                case ValueType::STRING:
                    return param.isString();
                case ValueType::ARRAY:
                    return param.isArray();
                case ValueType::OBJECT:
                    return param.isObject();
                }
                return false;
            }

        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using ParamDescribe = std::pair<std::string, ValueType>; // 参数描述：参数名称，参数类型
            using ServerCallback = std::function<void(const Json::Value &, Json::Value &)>;

            ServiceDescribe(std::string &&method, std::vector<ParamDescribe> &&param_descs, ServerCallback&& cb, ValueType ret_type)
                : _method_name(std::move(method))
                , _param_descs(std::move(param_descs))
                , _callback(std::move(cb))
                , _ret_type(ret_type)
            {
            }

            const std::string &method()
            {
                return _method_name;
            }

            bool paramCheck(const Json::Value &params)
            {
                for (auto param : _param_descs)
                {
                    if (params[param.first].isNull() == true)
                    {
                        ELOG("param [%s] missing", param.first.c_str());
                        return false;
                    }

                    if (check(param.second, params[param.first]) == false)
                    {
                        ELOG("param type [%s] verify failed", param.first.c_str());
                        return false;
                    }
                }
                return true;
            }

            bool call(const Json::Value &params, Json::Value &result)
            {
                _callback(params, result);
                if (check(_ret_type, result) == false)
                {
                    ELOG("result type verify failed");
                    return false;
                }
                return true;
            }

        private:
            std::string _method_name;
            // std::unordered_map<std::string, ParamDescribe> _param_descs; // 乱写!
            std::vector<ParamDescribe> _param_descs;
            ServerCallback _callback; // 业务处理函数
            ValueType _ret_type;      // 结果返回值类型
        };

        class ServiceDescribeFactory
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribeFactory>;

            void setMethod(std::string method)
            {
                _method_name = method;
            }

            void setParamDesc(const std::string &param_name, const ValueType &type)
            {
                ServiceDescribe::ParamDescribe param = std::make_pair(param_name, type);
                _param_descs.push_back(param);
            }

            void setCallback(ServiceDescribe::ServerCallback cb)
            {
                _callback = cb;
            }

            void setReturnType(ValueType ret_type)
            {
                _ret_type = ret_type;
            }

            ServiceDescribe::ptr build()
            {
                return std::make_shared<ServiceDescribe>(std::move(_method_name), std::move(_param_descs),
                                                        std::move(_callback), _ret_type);
            }

        private:
            std::string _method_name;
            std::vector<ServiceDescribe::ParamDescribe> _param_descs;
            ServiceDescribe::ServerCallback _callback; // 业务处理函数
            ValueType _ret_type;                      // 结果返回值类型
        };

        class ServiceManager
        {
        public:
            using ptr = std::shared_ptr<ServiceManager>;
            void insert(const ServiceDescribe::ptr &desc)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _services.insert(std::make_pair(desc->method(), desc));
            }

            ServiceDescribe::ptr select(const std::string &method)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _services.find(method);
                if (it == _services.end())
                {
                    return ServiceDescribe::ptr(); // 返回一个空的智能指针
                }
                return it->second;
            }

            void erase(const std::string &method)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _services.erase(method);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ServiceDescribe::ptr> _services; // 服务方法, 服务描述
        };

        class RpcRouter
        {
        private:
            void response(const BaseConnection::ptr &conn, const RpcRequest::ptr &req, const Json::Value &res, RCODE rcode)
            {
                RpcResponse::ptr rsp = MessageFactory::create<RpcResponse>();
                std::string id = req->id();
                rsp->setId(id);
                rsp->setMsgType(MSG_TYPE::RSP_RPC);
                rsp->setRcode(rcode);
                rsp->setResult(res);

                conn->send(rsp);
            }

        public:
            using ptr = std::shared_ptr<RpcRouter>;
            // RpcRouter(ServerManager::ptr manager) : _service_manager(manager) {} // 乱写
            RpcRouter()
            {
                _service_manager = std::make_shared<ServiceManager>();
            }

            void registerService(const ServiceDescribe::ptr &desc)
            {
                _service_manager->insert(desc);
            }

            // 注册到dispatcher模块的、针对Rpc请求回调处理的业务函数
            void onRpcRequest(const BaseConnection::ptr &conn, const RpcRequest::ptr &req)
            {
                std::string method = req->method();
                ServiceDescribe::ptr it = _service_manager->select(method);
                if (it.get() == nullptr)
                {
                    ELOG("[%s] service not found", method.c_str());
                    response(conn, req, Json::Value(), RCODE::RCODE_NOT_FOUND_SERVICE);
                    return;
                }

                Json::Value params = req->params();
                if (it->paramCheck(params) == false)
                {
                    ELOG("[%s] service param verify error", method.c_str());
                    response(conn, req, Json::Value(), RCODE::RCODE_INVALID_PARAM);
                    return;
                }

                Json::Value result;
                bool n = it->call(params, result); // call 内部封装了对result的参数类型校验
                if (n == false)
                {
                    ELOG("[%s] service param verify error", method.c_str());
                    response(conn, req, Json::Value(), RCODE::RCODE_INTERNAL_ERROR);
                    return;
                }

                response(conn, req, result, RCODE::RCODE_OK);
                return;
            }

        private:
            ServiceManager::ptr _service_manager;
        };
    }
}
